﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;


namespace Ruandao.Web
{
    public enum ResponseMode
    {
        Default,
        CSharpCode,
        Text,
    }

    public class Resource
    {
        private string fullPathName = "";

        public string FullPathName
        {
            get { return fullPathName; }
            set { fullPathName = value; }
        }

        private ResponseMode responseMode = ResponseMode.Default;

        public ResponseMode ResponseMode
        {
            get { return responseMode; }
            set { responseMode = value; }
        }

        private byte[] content;

        public byte[] Content
        {
            get { return content; }
            set { content = value; }
        }

    }

    public delegate bool ResourceHandler(string path, Resource resource);

    public abstract class ResourceModuleBase : IHttpModule
    {
        protected Dictionary<string, ResourceHandler> resourceTypes = new Dictionary<string, ResourceHandler>();

        #region IHttpModule 成员

        public void Dispose()
        {
            //;
        }

        public void Init(HttpApplication context)
        {
            RegisterResource();
            context.BeginRequest += (new EventHandler(this.Application_BeginRequest));
        }

        #endregion

        public abstract void RegisterResource();

        private void Application_BeginRequest(Object source, EventArgs e)
        {

            string requestPath = HttpContext.Current.Request.Path.ToLower();
            string appPath = HttpContext.Current.Request.ApplicationPath;

            string pathSource = requestPath.Substring(appPath.Length);

            // 去掉打头的 "/"字符。
            if (pathSource.StartsWith("/"))
            {
                pathSource = pathSource.Substring(1);
            }
            int pos = pathSource.IndexOf('/');
            string resourceName = "";

            if (pos == -1) return;
            else resourceName = pathSource.Substring(0, pos);

            // 不是模块索要处理的资源。
            if (!resourceTypes.ContainsKey(resourceName)) return;

            ResourceHandler handler = resourceTypes[resourceName];

            Resource resource = new Resource();
            handler(pathSource.Substring(pos + 1), resource);

            // 处理返回的resource中的资源
            if (resource.FullPathName != "")
            // 返回的资源是文件的全路径名。
            {
                switch (resource.ResponseMode)
                {
                    case ResponseMode.Default:
                        ResponseFile(resource.FullPathName);
                        break;
                    case ResponseMode.Text:
                        ResponseTextFile(resource.FullPathName);
                        break;
                    case ResponseMode.CSharpCode:
                        ResponseCSharpCodeFile(resource.FullPathName);
                        break;
                    default:
                        ResponseFile(resource.FullPathName);
                        break;
                }
            }
            else
            // 返回的资源是字节数组
            {
                switch (resource.ResponseMode)
                {
                    case ResponseMode.Default:
                        ResponseContent(resource.FullPathName);
                        break;
                    case ResponseMode.Text:
                        ResponseTextContent(resource.FullPathName);
                        break;
                    case ResponseMode.CSharpCode:
                        ResponseCSharpCodeContent(resource.FullPathName);
                        break;
                    default:
                        ResponseContent(resource.FullPathName);
                        break;
                }
            }

            HttpContext.Current.Response.End();

        }

        private void ResponseCSharpCodeContent(string path)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private void ResponseTextContent(string path)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private void ResponseContent(string path)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private void ResponseCSharpCodeFile(string path)
        {
            HttpContext.Current.Response.Write(StartHtmlFile());
            HttpContext.Current.Response.Write(GrammarRender.HtmlRender(path));
            HttpContext.Current.Response.Write(EndHtmlFile());
            WriteResponseHead(".html");
        }

        private void ResponseTextFile(string path)
        {
            Encoding code = TextFileEncoding.GetEncoding(path);
            StreamReader sr = new StreamReader(path, code);
            StringBuilder sb = new StringBuilder();
            for (; ; )
            {
                string s = sr.ReadLine();
                if (s == null) break;
                for (int i = 0; i != s.Length; i++)
                {
                    string dst;
                    switch (s[i])
                    {
                        case '<': dst = "&lt;"; break;
                        case '>': dst = "&gt;"; break;
                        case '&': dst = "&amp;"; break;
                        case ' ': dst = "&nbsp;"; break;
                        default: dst = new string(s[i], 1); break;
                    }
                    sb.Append(dst);
                }
                sb.Append("<br/>");
            }
            HttpContext.Current.Response.Write(StartHtmlFile());
            HttpContext.Current.Response.Write(sb.ToString());
            HttpContext.Current.Response.Write(EndHtmlFile());
            WriteResponseHead(".html");
        }

        private void ResponseFile(string path)
        {
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                OutputToResponse(fs);
            }

            string ext = Path.GetExtension(path);
            WriteResponseHead(ext);
        }


        private void OutputToResponse(FileStream fileStream)
        {
            int count = 0;
            byte[] buffer = new byte[2048];
            while (true)
            {
                count = fileStream.Read(buffer, 0, 2048);
                if (count == 0) break;
                HttpContext.Current.Response.OutputStream.Write(buffer, 0, count);
            }
        }
        /// <summary>
        /// 根据所请求文件的扩展名，填充Response的头部信息，比如MIME等。
        /// </summary>
        /// <param name="ext"></param>
        private void WriteResponseHead(string fileExt)
        {
            /*
             * text/plain
             * text/html
             * image/gif
             * image/jpeg
             * application/msword
             * video/mpeg
             * audio/wave
             * 
             */
            string mimeType = "";
            switch (fileExt.ToLower())
            {
                case ".html":
                case ".htm":
                case ".xhtml":
                    mimeType = "text/html";
                    break;

                case ".jpg":
                case ".jpeg":
                    mimeType = "image/jpeg";
                    break;
                case ".gif":
                    mimeType = "image/gif";
                    break;
                case ".bmp":
                case ".png":
                case ".pcx":
                    break;

                case ".css":
                    break;

                case ".xml":
                    break;

                case ".txt":
                    mimeType = "text/plain";
                    break;
                case ".wmf":
                    mimeType = "video/wmf";
                    break;
                case ".mpg":
                    mimeType = "video/mpg";
                    break;
                case ".avi":
                    mimeType = "video/avi";
                    break;

                default:
                    break;
            }
            HttpContext.Current.Response.ContentType = mimeType;
        }

        private string StartHtmlFile()
        {
            return @"
<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">

<html xmlns=""http://www.w3.org/1999/xhtml"" >
<head>
    <title>无标题页</title>
</head>
<body>
";
        }

        private string EndHtmlFile()
        {
            return @"
</body>
</html>
";
        }

    }
}
